import { app, BrowserWindow, globalShortcut, dialog, shell, ipcMain } from 'electron'
import path from 'path'
import './ipcHandlers'
import { logger } from './logger'
import { promises as fs } from 'fs'
import { execFile } from 'child_process'

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) {
  app.quit()
}

let mainWindow: BrowserWindow | null = null
let rendererReady = false
let preheatWindow: BrowserWindow | null = null

// 创建隐藏预热窗口（用于保持渲染进程与缓存预热）
const createPreheatWindow = () => {
  try {
    if (preheatWindow && !preheatWindow.isDestroyed()) return
    preheatWindow = new BrowserWindow({
      width: 800,
      height: 600,
      show: false,
      frame: false,
      webPreferences: {
        preload: path.join(__dirname, 'preload.js'),
        nodeIntegration: false,
        contextIsolation: true,
        webSecurity: false
      }
    })

    preheatWindow.on('closed', () => {
      preheatWindow = null
    })

    if (process.env.NODE_ENV === 'development') {
      preheatWindow.loadURL(process.env.VITE_DEV_SERVER_URL || 'http://localhost:3001')
    } else {
      preheatWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
    }
  } catch {
    try { preheatWindow?.destroy() } catch {}
    preheatWindow = null
  }
}

// 处理文件打开的函数
const handleFileOpen = async (filePath: string) => {
  try {
    if (!filePath || !filePath.endsWith('.md')) {
      logger.warn('无效的文件路径或非.md文件:', filePath)
      return
    }

    // 检查文件是否存在
    const exists = await fs.access(filePath).then(() => true).catch(() => false)
    if (!exists) {
      logger.warn('文件不存在:', filePath)
      return
    }

    // 读取文件内容
    const content = await fs.readFile(filePath, 'utf-8')
    logger.info('通过文件关联打开文件:', filePath)

    // 如果窗口已存在，直接发送文件内容
    if (mainWindow && !mainWindow.isDestroyed()) {
      mainWindow.webContents.send('file-opened', { filePath, content })
      mainWindow.focus() // 聚焦到窗口
    } else {
      // 如果窗口不存在，创建窗口后再发送
      createWindow()
      mainWindow?.webContents.once('did-finish-load', () => {
        mainWindow?.webContents.send('file-opened', { filePath, content })
      })
    }
  } catch (error) {
    logger.error('处理文件打开失败:', error)
  }
}

// 创建新的编辑窗口（支持可选启动文件）
const createEditorWindow = (startupFile?: string): BrowserWindow => {
  // 创建新窗口前，如存在预热窗口则释放以节省资源
  if (preheatWindow && !preheatWindow.isDestroyed()) {
    try { preheatWindow.destroy() } catch {}
    preheatWindow = null
  }
  const win = new BrowserWindow({
    width: 1200,
    height: 800,
    frame: false,
    autoHideMenuBar: true,
    show: false,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: false,
      contextIsolation: true,
      webSecurity: false
    }
  })

  win.once('ready-to-show', () => {
    try {
      win.maximize()
      win.show()
    } catch {}
  })

  // 独立窗口的关闭前检查
  win.on('close', async (event) => {
    event.preventDefault()
    try {
      const shouldClose = await win.webContents.executeJavaScript(`
        (async () => {
          try {
            const api = window.electronAPI;
            if (api && typeof api.callCheckBeforeClose === 'function') {
              const result = await api.callCheckBeforeClose();
              return result;
            }
            return true;
          } catch (error) { return false }
        })()
      `)
      if (shouldClose) {
        win.destroy()
      }
    } catch (err) {
      logger.warn('编辑器窗口关闭检查异常，已阻止关闭', err)
      // 发生错误时不要强制关闭，避免绕过未保存提示
    }
  })

  // 关闭后，如没有任何窗口，进行预热并释放全局快捷键
  win.on('closed', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      try { globalShortcut.unregisterAll() } catch {}
      createPreheatWindow()
    }
  })

  // 加载页面
  if (process.env.NODE_ENV === 'development') {
    win.loadURL(process.env.VITE_DEV_SERVER_URL || 'http://localhost:3001')
    win.webContents.on('did-frame-finish-load', () => {
      if (process.env.NODE_ENV === 'development') {
        try { win.webContents.openDevTools() } catch {}
      }
    })
  } else {
    win.loadFile(path.join(__dirname, '../renderer/index.html'))
  }

  // 等待渲染侧就绪后再发送启动内容，避免事件监听尚未绑定导致丢失
  const sendStartupPayload = async () => {
    try {
      if (startupFile) {
        const exists = await fs.access(startupFile).then(() => true).catch(() => false)
        if (!exists) {
          logger.warn('文件不存在:', startupFile)
          return
        }
        const content = await fs.readFile(startupFile, 'utf-8')
        win.webContents.send('file-opened', { filePath: startupFile, content })
      } else {
        win.webContents.send('startup-complete')
      }
    } catch (e) {
      logger.error('新窗口发送启动内容失败:', e)
    }
  }

  const onRendererReady = (event: Electron.IpcMainEvent) => {
    try {
      if (event?.sender === win.webContents) {
        ipcMain.removeListener('renderer-ready', onRendererReady)
        if (win.webContents.isLoading()) {
          win.webContents.once('did-finish-load', () => { void sendStartupPayload() })
        } else {
          void sendStartupPayload()
        }
      }
    } catch (e) {
      logger.warn('处理renderer-ready事件失败', e)
    }
  }
  ipcMain.on('renderer-ready', onRendererReady)

  return win
}

// 从命令行参数中获取要打开的文件（支持 .md/.markdown，大小写不敏感，去除引号）
const getFileFromArgs = (): string | null => {
  const raw = process.argv.slice(app.isPackaged ? 1 : 2)
  const args = raw.map(a => a.replace(/^"+|"+$/g, '').trim())
  logger.info('命令行参数:', args)
  const mdFile = args.find(arg => /\.(md|markdown)$/i.test(arg) && !arg.startsWith('-'))
  return mdFile || null
}

// 检查当前应用是否为 .md 文件默认编辑器（仅 Windows）
const queryRegistry = (key: string, valueName?: string): Promise<string | null> => {
  return new Promise((resolve) => {
    execFile(
      'reg.exe',
      ['query', key].concat(valueName ? ['/v', valueName] : []),
      { windowsHide: true },
      (err, stdout) => {
        if (err) { resolve(null); return }
        resolve(stdout?.toString() || null)
      }
    )
  })
}

const getCurrentMdOpenCommand = async (): Promise<string | null> => {
  // 首选 UserChoice 的 ProgId
  const userChoice = await queryRegistry('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\.md\\UserChoice', 'ProgId')
  let progId: string | null = null
  if (userChoice) {
    const m = userChoice.match(/ProgId\s+REG_SZ\s+([^\r\n]+)/)
    if (m) progId = m[1].trim()
  }
  // 退回到 Classes 的默认值
  if (!progId) {
    const classes = await queryRegistry('HKCU\\Software\\Classes\\.md')
    if (classes) {
      const m = classes.match(/REG_SZ\s+([^\r\n]+)/)
      if (m) progId = m[1].trim()
    }
  }
  if (!progId) return null

  // 通过 ProgId 查找 open 命令
  const hkcuCmd = await queryRegistry(`HKCU\\Software\\Classes\\${progId}\\shell\\open\\command`)
  const hklmCmd = hkcuCmd ? null : await queryRegistry(`HKLM\\Software\\Classes\\${progId}\\shell\\open\\command`)
  const output = hkcuCmd || hklmCmd
  if (!output) return null
  const m = output.match(/REG_SZ\s+([^\r\n]+)/)
  return m ? m[1].trim() : null
}

const isDefaultMdEditorWindows = async (): Promise<boolean> => {
  const cmd = await getCurrentMdOpenCommand()
  if (!cmd) return false
  const match = cmd.match(/"([^"]+\\.exe)"/) || cmd.match(/([^\s]+\\.exe)/)
  const exe = match ? match[1] : ''
  if (!exe) return false
  const ourExe = app.getPath('exe')
  const normalize = (p: string) => p.replace(/"/g, '').trim().toLowerCase()
  return normalize(exe) === normalize(ourExe)
}

// 静默写注册表设置 .md 关联到当前应用
const setRegistryValue = (key: string, valueName?: string, type: string = 'REG_SZ', data?: string) => {
  return new Promise<boolean>((resolve) => {
    const args = ['add', key, '/f']
    if (valueName) args.push('/v', valueName)
    if (type) args.push('/t', type)
    if (typeof data !== 'undefined') args.push('/d', String(data))
    execFile('reg.exe', args, { windowsHide: true }, (err) => {
      resolve(!err)
    })
  })
}

const ensureMdAssociation = async () => {
  try {
    if (process.platform !== 'win32') return
    if (!app.isPackaged) {
      logger.info('开发环境跳过注册表关联设置')
      return
    }

    const isDefault = await isDefaultMdEditorWindows()
    logger.info('默认编辑器检查(静默): ', { isDefault })
    if (isDefault) return

    const progId = 'MarkGod.md'
    const exePath = app.getPath('exe')
    const command = `"${exePath}" "%1"`

    // 定义ProgId并设置打开命令
    await setRegistryValue(`HKCU\\Software\\Classes\\${progId}`)
    await setRegistryValue(`HKCU\\Software\\Classes\\${progId}\\shell\\open\\command`, undefined, 'REG_SZ', command)

    // 将 .md 的默认值指向我们的 ProgId
    await setRegistryValue('HKCU\\Software\\Classes\\.md', undefined, 'REG_SZ', progId)
    // 提示系统我们的应用可打开 .md
    await setRegistryValue('HKCU\\Software\\Classes\\.md\\OpenWithProgIds', progId, 'REG_SZ', '')
    // 额外的类型提示（可选）
    await setRegistryValue('HKCU\\Software\\Classes\\.md', 'PerceivedType', 'REG_SZ', 'text')
    await setRegistryValue('HKCU\\Software\\Classes\\.md', 'Content Type', 'REG_SZ', 'text/markdown')

    // Applications 路径（让“打开方式”列表里出现我们的应用）
    const exeName = path.basename(app.getPath('exe'))
    await setRegistryValue(`HKCU\\Software\\Classes\\Applications\\${exeName}\\shell\\open\\command`, undefined, 'REG_SZ', command)

    const ok = await isDefaultMdEditorWindows()
    logger.info('静默设置默认编辑器完成', { success: ok })
  } catch (e) {
    logger.warn('静默设置默认编辑器失败', e)
  }
}

const createWindow = () => {
  // 创建主窗口前，如存在预热窗口则释放以节省资源
  if (preheatWindow && !preheatWindow.isDestroyed()) {
    try { preheatWindow.destroy() } catch {}
    preheatWindow = null
  }
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    frame: false, // 去掉窗口边框
    autoHideMenuBar: true, // 自动隐藏菜单栏
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: false, // 禁用nodeIntegration以提高安全性
      contextIsolation: true,  // 启用contextIsolation以使用contextBridge
      webSecurity: false // 允许加载本地文件资源
    }
  })

  // 默认最大化窗口
  try { mainWindow.maximize() } catch {}

  // 监听窗口关闭事件
  mainWindow.on('close', async (event) => {
    event.preventDefault() // 阻止默认关闭行为
    
    try {
      logger.info('窗口关闭事件被触发')
      
      // 调用渲染进程的检查函数
      const shouldClose = await mainWindow!.webContents.executeJavaScript(`
        (async () => {
          try {
            console.log('主进程正在执行渲染脚本进行关闭前检查');
            const api = window.electronAPI;
            console.log('window.electronAPI存在:', !!api);
            console.log('callCheckBeforeClose类型:', typeof api?.callCheckBeforeClose);
            
            if (api && typeof api.callCheckBeforeClose === 'function') {
              console.log('调用callCheckBeforeClose...');
              const result = await api.callCheckBeforeClose();
              console.log('关闭前检查处理器返回结果:', result);
              return result;
            } else {
              console.log('未找到callCheckBeforeClose，默认允许关闭');
              return true;
            }
          } catch (error) {
            console.error('执行关闭检查失败:', error);
            return false;
          }
        })()
      `)
      
      logger.info('关闭前检查结果:', shouldClose)
      
      if (shouldClose) {
        logger.info('允许关闭窗口')
        mainWindow!.destroy() // 强制关闭窗口
      } else {
        logger.info('阻止关闭窗口')
      }
    } catch (error) {
      logger.error('检查关闭前状态时出错（主窗口）:', error)
      // 发生错误时不要强制关闭，避免绕过未保存提示
    }
  })

  // 主窗口关闭后，如没有任何窗口，进行预热并释放全局快捷键
  mainWindow.on('closed', () => {
    mainWindow = null
    if (BrowserWindow.getAllWindows().length === 0) {
      try { globalShortcut.unregisterAll() } catch {}
      createPreheatWindow()
    }
  })

  // and load the index.html of the app.
  if (process.env.NODE_ENV === 'development') {
    mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL || 'http://localhost:3001')
    
    // 开发模式下启用热重载
    if (process.env.NODE_ENV === 'development') {
      // 监听渲染进程的重载
      mainWindow.webContents.on('did-frame-finish-load', () => {
        if (process.env.NODE_ENV === 'development') {
          mainWindow?.webContents.openDevTools()
        }
      })
    }
  } else {
    mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
  }

  // 等待页面加载完成后添加调试信息
  mainWindow.webContents.once('dom-ready', () => {
    logger.info('DOM已准备就绪')
  })

  // Open the DevTools.
  if (process.env.NODE_ENV === 'development') {
    mainWindow.webContents.openDevTools()
  }
  
  // 添加快捷键：Ctrl+Shift+I 打开开发者工具
  globalShortcut.register('CommandOrControl+Shift+I', () => {
    const focused = BrowserWindow.getFocusedWindow()
    focused?.webContents.openDevTools()
  })
  
  // 添加快捷键：F12 打开开发者工具
  globalShortcut.register('F12', () => {
    const focused = BrowserWindow.getFocusedWindow()
    focused?.webContents.openDevTools()
  })
  
  // 添加快捷键：Ctrl+R 重载页面
  globalShortcut.register('CommandOrControl+R', () => {
    if (process.env.NODE_ENV === 'development') {
      const focused = BrowserWindow.getFocusedWindow()
      focused?.webContents.reload()
    }
  })
  
  // 添加快捷键：F5 重载页面
  globalShortcut.register('F5', () => {
    if (process.env.NODE_ENV === 'development') {
      const focused = BrowserWindow.getFocusedWindow()
      focused?.webContents.reload()
    }
  })
}

// 热重载支持 - 在开发模式下重启应用
if (process.env.NODE_ENV === 'development') {
  // 监听主进程文件变化（由nodemon处理）
  process.on('SIGUSR2', () => {
    app.quit()
  })
}

// 确保单实例运行，并处理文件关联
const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  // 如果获取不到锁，说明已有实例在运行，退出当前实例
  app.quit()
} else {
  // 处理第二个实例尝试启动时的情况
  app.on('second-instance', (event, commandLine, workingDirectory) => {
    logger.info('检测到第二个实例启动', { commandLine, workingDirectory })
    
    // 处理新的文件参数
    const args = commandLine.slice(app.isPackaged ? 1 : 2).map(a => a.replace(/^"+|"+$/g, '').trim())
    const mdFile = args.find(arg => /\.(md|markdown)$/i.test(arg) && !arg.startsWith('-'))
    if (mdFile) {
      try { createEditorWindow(mdFile) } catch (e) { logger.error('创建新窗口失败:', e) }
    } else {
      // 无文件参数时，聚焦到现有主窗口；若不存在则创建
      if (mainWindow && !mainWindow.isDestroyed()) {
        if (mainWindow.isMinimized()) mainWindow.restore()
        mainWindow.focus()
      } else {
        createWindow()
      }
    }
  })

  // macOS：通过 Finder 打开 .md 文件时，创建新窗体
  app.on('open-file', (event, filePath) => {
    event.preventDefault()
    try {
      if (app.isReady()) {
        createEditorWindow(filePath)
      } else {
        app.once('ready', () => createEditorWindow(filePath))
      }
    } catch (e) {
      logger.error('处理 open-file 事件失败:', e)
    }
  })

  // This method will be called when Electron has finished
  // initialization and is ready to create browser windows.
  // Some APIs can only be used after this event occurs.
  app.on('ready', async () => {
    createWindow()
    ensureMdAssociation()
    // 监听渲染就绪信号
    ipcMain.on('renderer-ready', () => {
      rendererReady = true
      logger.info('收到renderer-ready信号')
      // 启动完成后，若无启动文件，通知渲染侧可以加载默认内容
      if (mainWindow && !mainWindow.isDestroyed()) {
        const fileToOpen = getFileFromArgs()
        if (!fileToOpen) {
          mainWindow.webContents.send('startup-complete')
        }
      }
    })
    
    // 检查启动时是否有文件参数
    const fileToOpen = getFileFromArgs()
    if (fileToOpen) {
      // 等待窗口与渲染侧就绪后打开文件
      mainWindow?.webContents.once('did-finish-load', () => {
        const sendFile = () => handleFileOpen(fileToOpen)
        if (rendererReady) {
          sendFile()
        } else {
          ipcMain.once('renderer-ready', () => sendFile())
        }
      })
    }
  })
}

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  // 注销所有快捷键
  globalShortcut.unregisterAll()
  // 保持应用常驻以加速后续打开文件（不退出主进程）
  try { createPreheatWindow() } catch {}
})

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow()
  }
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.